package com.esproject.esutils;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.InternalFilter;
import org.elasticsearch.search.aggregations.bucket.range.InternalRange;
import org.elasticsearch.search.aggregations.bucket.range.RangeBuilder;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsBuilder;
import org.elasticsearch.search.highlight.HighlightField;
import org.elasticsearch.search.suggest.Suggest;
import org.elasticsearch.search.suggest.completion.CompletionSuggestionBuilder;
import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;

import com.alibaba.fastjson.JSON;
import com.esproject.bean.CvInfo;
import com.esproject.bean.ResultItermBean;
import com.esproject.esFactory.ElasticClientFactory;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

/**
 * Created by yan_li on 2017/2/20.
 */
public class SearchUtil {

    public static void searchByPrex(String indexName, String typeName, String field, String value) {
        SearchRequestBuilder builder = ElasticClientFactory.getClient().prepareSearch(indexName);
        builder.setTypes(typeName);
        //        builder.setFrom(0);
        builder.setSize(2214);
        builder.setQuery(QueryBuilders.matchPhraseQuery(field, value).slop(4));//对value进行分词操作,并且查询词分词后之间最多允许4个
        // builder.setQuery(QueryBuilders.matchQuery(field, value));//会对value进行分词操作
        builder.setSearchType(SearchType.QUERY_THEN_FETCH);
        //builder.addSort("months", SortOrder.ASC);
        builder.setExplain(true);
        SearchResponse response = builder.execute().actionGet();
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        System.out.println("命中个数:" + hits.getTotalHits());
        for (SearchHit hit : searchHits) {
            System.out.println(hit.score() + "" + hit.getSource());
            // System.out.println(hit.score()+"==="+);
        }
        System.out.println("-->" + response.toString());
    }

    public static Map<String, Object> Highlighter(String indexName, String typeName, Map<String, String> filterKey, String searchfield, String value, int pageSize, int pageNum) {
        try {
            Map<String, Object> parames = Maps.newHashMap();
            List<CvInfo> cvLists = Lists.newArrayList();
            QueryBuilder boolQueryBuilder = null;
            //组合查询
            if (filterKey != null && filterKey.size() > 0) {
                boolQueryBuilder = filterBuilderMaker(filterKey).must(QueryBuilders.matchQuery(searchfield, value).slop(5).minimumShouldMatch("90"));
            } else {
                boolQueryBuilder = QueryBuilders.matchPhraseQuery(searchfield, value).slop(5);
            }
            System.out.println(boolQueryBuilder.toString());
            SearchRequestBuilder builder = ElasticClientFactory.getClient().prepareSearch(indexName);
            builder.setTypes(typeName);
            builder.setFrom(pageNum);
            builder.setSize(pageSize);
            //设置高亮字段名称
            builder.addHighlightedField(searchfield);
            //设置高亮前缀
            builder.setHighlighterPreTags("<font color='red' >");
            //设置高亮后缀
            builder.setHighlighterPostTags("</font>");
            builder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
            builder.setQuery(boolQueryBuilder);
            //builder.setExplain(true);
            SearchResponse searchResponse = builder.get();
            SearchHits hits = searchResponse.getHits();
            SearchHit[] hitsGet = hits.getHits();
            parames.put("total", hits.getTotalHits());
            for (SearchHit hit : hitsGet) {
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                HighlightField highlightField = highlightFields.get(searchfield);
                Map<String, Object> source = hit.getSource();
                if (highlightField != null) {
                    Text[] fragments = highlightField.fragments();
                    String name = "";
                    for (Text text : fragments) {
                        name += text;
                    }
                    source.put(searchfield, name);
                }
                CvInfo cvInfo = JSON.parseObject(JSON.toJSONString(source), CvInfo.class);
                cvLists.add(cvInfo);
            }
            parames.put("value", cvLists);
            return parames;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * term fact
     *
     * @param indexName
     * @param typeName
     * @param factField
     * @param value
     * @return
     */
    public static List<ResultItermBean> ternFact(String indexName, String typeName, String factField, String searchField, String value) {
        List<ResultItermBean> eduBeanList = Lists.newArrayList();
        MatchQueryBuilder boolQueryBuilder = QueryBuilders.matchPhraseQuery(searchField, value).slop(5);
        //构造一个过滤分组器
        FilterAggregationBuilder filterGroup = AggregationBuilders.filter("filterGroup").filter(boolQueryBuilder);
        TermsBuilder eduAgg = AggregationBuilders.terms("termfac").field(factField);
        filterGroup.subAggregation(eduAgg);
        SearchRequestBuilder req = ElasticClientFactory.getClient().prepareSearch(indexName);
        req.setTypes(typeName);
        req.addAggregation(filterGroup);
        SearchResponse rep = req.execute().actionGet();
        InternalFilter filterSt = (InternalFilter) rep.getAggregations().asMap().get("filterGroup");
        StringTerms st = (StringTerms) filterSt.getAggregations().asMap().get("termfac");
        for (Terms.Bucket stm : st.getBuckets()) {
            System.out.println(stm.getKey() + "---" + stm.getDocCount());
            ResultItermBean eduBean = new ResultItermBean();
            eduBean.setName((String) stm.getKey());
            eduBean.setCount(stm.getDocCount());
            eduBeanList.add(eduBean);
        }
        return eduBeanList;
    }

    /**
     * rang fact
     *
     * @param indexName
     * @param typeName
     * @param field
     * @param value
     * @return
     */
    public static List<ResultItermBean> rangFact(String indexName, String typeName, Map<String, String> fieldValue, String searchField, String value) {
        List<ResultItermBean> yearBeanList = Lists.newArrayList();
        BoolQueryBuilder boolQueryBuilder = filterBuilderMaker(fieldValue).must(QueryBuilders.matchPhraseQuery(searchField, value).slop(5));
        //构造一个过滤分组器
        FilterAggregationBuilder filterGroup = AggregationBuilders.filter("filterGroup").filter(boolQueryBuilder);
        RangeBuilder rangeBuilder = AggregationBuilders.range("workTimeRange").field("workTime").addRange(0, 24).addRange(24, 48).addRange(48, 10000);
        filterGroup.subAggregation(rangeBuilder);
        SearchRequestBuilder req = ElasticClientFactory.getClient().prepareSearch(indexName);
        req.setTypes(typeName);
        req.addAggregation(filterGroup);
        SearchResponse rep = req.execute().actionGet();
        InternalFilter filterSt = (InternalFilter) rep.getAggregations().asMap().get("filterGroup");
        InternalRange monthStm = (InternalRange) filterSt.getAggregations().asMap().get("workTimeRange");
        List<InternalRange.Bucket> buckets = monthStm.getBuckets();
        for (InternalRange.Bucket b : buckets) {
            System.out.println(b.getKey() + "---" + b.getDocCount());
            ResultItermBean monthBean = new ResultItermBean();
            monthBean.setName(b.getKey());
            monthBean.setCount(b.getDocCount());
            yearBeanList.add(monthBean);
        }
        return yearBeanList;
    }

    /**
     * 高亮、切面统计 合并使用demo
     *
     * @param indexName
     * @param typeName
     * @param filterKey
     * @param HighlightedField
     * @param keyWords
     * @param pageSize
     * @param pageNum
     * @return
     */
    public static Map<String, Object> HighlighterWithFact(String indexName, String typeName, Map<String, String> filterKey, String HighlightedField, String keyWords, int pageSize, int pageNum) {
        Map<String, Object> parames = Maps.newHashMap();
        List<CvInfo> cvLists = Lists.newArrayList();
        List<ResultItermBean> eduBeanList = Lists.newArrayList();
        List<ResultItermBean> yearBeanList = Lists.newArrayList();

        BoolQueryBuilder boolQueryBuilder = filterBuilderMaker(filterKey).must(QueryBuilders.matchQuery(HighlightedField, keyWords));
        //构造一个过滤分组器
        FilterAggregationBuilder filterGroup = AggregationBuilders.filter("filterGroup").filter(boolQueryBuilder);
        //计数聚合器
        TermsBuilder eduAgg = AggregationBuilders.terms("eduGroup").field("edu");
        //范围聚合器
        RangeBuilder rangeBuilder = AggregationBuilders.range("workTimeRange").field("workTime").addRange(0, 24).addRange(24, 48).addRange(48, 10000);
        //组合一起 组合顺序很重要
        TermsBuilder termsBuilder = eduAgg.subAggregation(rangeBuilder);
        filterGroup.subAggregation(termsBuilder);

        SearchRequestBuilder builder = ElasticClientFactory.getClient().prepareSearch(indexName);
        builder.setTypes(typeName);
        builder.setFrom(pageNum);
        builder.setSize(pageSize);
        //设置高亮字段名称
        builder.addHighlightedField(HighlightedField);
        //设置高亮前缀
        builder.setHighlighterPreTags("<font color='red' >");
        //设置高亮后缀
        builder.setHighlighterPostTags("</font>");
        builder.setSearchType(SearchType.DFS_QUERY_THEN_FETCH);
        builder.setQuery(boolQueryBuilder);
        builder.addAggregation(filterGroup);

        SearchResponse searchResponse = builder.get();
        SearchHits hits = searchResponse.getHits();
        SearchHit[] hitsGet = hits.getHits();
        parames.put("total", hits.getTotalHits());
        System.out.println(hits.getTotalHits());
        for (SearchHit hit : hitsGet) {
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            HighlightField highlightField = highlightFields.get(HighlightedField);
            Map<String, Object> source = hit.getSource();
            if (highlightField != null) {
                Text[] fragments = highlightField.fragments();
                String name = "";
                for (Text text : fragments) {
                    name += text;
                }
                source.put(HighlightedField, name);
            }
            CvInfo cvInfo = JSON.parseObject(JSON.toJSONString(source), CvInfo.class);
            cvLists.add(cvInfo);
        }

        InternalFilter filterSt = (InternalFilter) searchResponse.getAggregations().asMap().get("filterGroup");
        StringTerms st = (StringTerms) filterSt.getAggregations().asMap().get("eduGroup");
        for (Terms.Bucket stm : st.getBuckets()) {
            System.out.println(stm.getKey() + "---" + stm.getDocCount());
            ResultItermBean eduBean = new ResultItermBean();
            eduBean.setName((String) stm.getKey());
            eduBean.setCount(stm.getDocCount());
            eduBeanList.add(eduBean);
            InternalRange monthStm = (InternalRange) stm.getAggregations().asMap().get("workTimeRange");
            List<InternalRange.Bucket> buckets = monthStm.getBuckets();
            for (InternalRange.Bucket b : buckets) {
                ResultItermBean monthBean = new ResultItermBean();
                monthBean.setName(b.getKey());
                monthBean.setCount(stm.getDocCount());
                yearBeanList.add(monthBean);
            }
        }
        parames.put("value", cvLists);
        parames.put("eduList", eduBeanList);
        parames.put("yearList", yearBeanList);
        return parames;
    }

    /**
     * 多切面组合一起
     *
     * @param indexName
     * @param typeName
     * @param field
     * @param value
     */
    public static void faceFilter(String indexName, String typeName, String field, String value) {
        //定义名为eduGroup的桶,指标为分组count
        // TermsBuilder eduAgg = AggregationBuilders.terms("eduGroup").field("edu");
        //构造一个过滤分组器
        FilterAggregationBuilder filterGroup = AggregationBuilders.filter("filterGroup").filter(QueryBuilders.termQuery(field, value));
        //计数聚合器
        TermsBuilder eduAgg = AggregationBuilders.terms("eduGroup").field("edu");
        //范围聚合器
        RangeBuilder rangeBuilder = AggregationBuilders.range("workTimeRange").field("workTime").addRange(0, 24).addRange(24, 48).addRange(48, 10000);
        ;
        //组合一起 组合顺序很重要
        TermsBuilder termsBuilder = eduAgg.subAggregation(rangeBuilder);
        filterGroup.subAggregation(termsBuilder);

        Client client = ElasticClientFactory.getClient();
        SearchRequestBuilder req = client.prepareSearch(indexName);
        req.setTypes(typeName);
        req.addAggregation(filterGroup);
        req.setQuery(QueryBuilders.termQuery(field, value));
        SearchResponse searchResponse = req.execute().actionGet();
        SearchHit[] hits = searchResponse.getHits().getHits();
        System.out.println(searchResponse.getHits().getTotalHits());
        for (SearchHit hit : hits) {
            System.out.println(hit.getSource());
        }
        InternalFilter filterSt = (InternalFilter) searchResponse.getAggregations().asMap().get("filterGroup");
        StringTerms st = (StringTerms) filterSt.getAggregations().asMap().get("eduGroup");
        for (Terms.Bucket stm : st.getBuckets()) {
            System.out.println(stm.getKey() + "---" + stm.getDocCount());
            InternalRange monthStm = (InternalRange) stm.getAggregations().asMap().get("workTimeRange");
            List<InternalRange.Bucket> buckets = monthStm.getBuckets();
            for (InternalRange.Bucket b : buckets) {
                System.out.println("\t" + b.getKey() + " 工作年限在0到20个月的人数是" + b.getDocCount());
            }
        }
    }

    public static BoolQueryBuilder filterBuilderMaker(Map<String, String> map) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        for (Map.Entry<String, String> entry : map.entrySet()) {
            if (StringUtils.isNotBlank(entry.getValue())) {
                if (entry.getKey().equals("workTime")) {
                    String[] split = entry.getValue().split("-");
                    float from = Float.parseFloat(split[0]);
                    float to = Float.parseFloat(split[1]);
                    boolQueryBuilder.must(QueryBuilders.rangeQuery("workTime").from(from).to(to));
                } else {
                    boolQueryBuilder.must(QueryBuilders.termQuery(entry.getKey(), entry.getValue()));
                }
            }
        }
        return boolQueryBuilder;
    }

    /**
     * 搜索提示 自动补全
     * @param index
     * @param field
     * @param value
     */
    public static void searchSuggest(String index, String field, String value) {
        Client client = ElasticClientFactory.getClient();
        SearchRequestBuilder req = client.prepareSearch(index);
        req.setQuery(QueryBuilders.matchAllQuery());
        CompletionSuggestionBuilder csfb = new CompletionSuggestionBuilder("sug").field(field).text(value).size(100);
        req.addSuggestion(csfb);
        SearchResponse suggestResponse = req.execute().actionGet();
        List<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> results = suggestResponse.getSuggest().getSuggestion("sug").getEntries();
        System.out.println(JSON.toJSONString(suggestResponse));
        for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> op : results) {
            Text text = op.getText();
            System.out.println(text.toString());
            List<? extends Suggest.Suggestion.Entry.Option> options = op.getOptions();
            for (Suggest.Suggestion.Entry.Option pp : options) {
                System.out.println("\t" + pp.getText() + "==>" + pp.getScore());
            }
        }
    }

    /**
     * 搜索词建议(感觉中文没有提示)
     * @param index
     * @param field
     * @param value
     */
    public static void phraseSuggest(String index, String field, String value) {
        Client client = ElasticClientFactory.getClient();
        //        SearchRequestBuilder req = client.prepareSearch(index);
        //        // req.setQuery(QueryBuilders.matchAllQuery());
        //        TermSuggestionBuilder ps = new TermSuggestionBuilder("phres").field(field).text(value).size(100);
        //        req.addSuggestion(ps);
        //        SearchResponse suggestResponse = req.execute().actionGet();
        SearchResponse suggestResponse = client.prepareSearch(index).setQuery(QueryBuilders.matchAllQuery()).addSuggestion(new TermSuggestionBuilder("first_suggestion").suggestMode("always").text(value).analyzer("ik_smart").field("_all")).execute().actionGet();

        System.out.println(JSON.toJSONString(suggestResponse));
        List<? extends Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option>> phres = suggestResponse.getSuggest().getSuggestion("first_suggestion").getEntries();
        for (Suggest.Suggestion.Entry<? extends Suggest.Suggestion.Entry.Option> ops : phres) {
            System.out.println(ops.getText().toString());
            List<? extends Suggest.Suggestion.Entry.Option> options = ops.getOptions();
            for (Suggest.Suggestion.Entry.Option pp : options) {
                System.out.println("\t" + pp.getText() + "==>" + pp.getScore());
            }
        }
    }

    public static void main(String[] args) {
        // searchByPrex("cv_info", "cv_data", "expJob", "高级工程师");
        // Highlighter("cv_info", "cv_data", "expJob", "销售代表",10,0);
        //factCount("cv_info", "cv_data");
        // faceFilter("cv_info", "cv_data", "expJob", "销售");
        //hightLineFactTest();
        //ternFact("cv_info", "cv_data", "edu", "expJob", "销售代表");
        //        Map<String, String> searchFieldmaps = Maps.newHashMap();
        //        searchFieldmaps.put("edu", "本科");
        // rangFact("cv_info", "cv_data", searchFieldmaps, "expJob", "销售代表");

        //        Map<String, Object> highlighter = Highlighter("cv_info", "cv_data", searchFieldmaps, "expJob", "销售代表", 8, 0);
        //        System.out.println(JSON.toJSONString(highlighter));

        //searchSuggest("cv_info", "expJob", "销售");
        phraseSuggest("cv_info", "expJob", "jova");
    }

    public static void hightLineFactTest() {
        Map<String, String> searchFieldmaps = Maps.newHashMap();
        searchFieldmaps.put("edu", "本科");
        Map<String, Object> map = SearchUtil.HighlighterWithFact("cv_info", "cv_data", searchFieldmaps, "expJob", "销售代表", 10, 0);
        System.out.println(JSON.toJSONString(map));
    }
}
